package com.snail.oa.service.impl;

import cn.hutool.core.util.HexUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.snail.common.core.exception.ServiceException;
import com.snail.common.core.utils.PageUtils;
import com.snail.common.core.utils.StringUtils;
import com.snail.common.core.web.page.PageResult;
import com.snail.common.mq.core.dto.MqDto;
import com.snail.common.mq.core.dto.MqResultDto;
import com.snail.common.security.utils.SecurityUtils;
import com.snail.common.sequence.utils.SequenceUtils;
import com.snail.oa.domain.LeaveApply;
import com.snail.oa.mapper.LeaveApplyMapper;
import com.snail.oa.mq.KafkaConsumerService;
import com.snail.oa.mq.KafkaFileConsumerService;
import com.snail.oa.query.LeaveApplyQuery;
import com.snail.oa.service.ILeaveApplyService;
import com.snail.workflow.api.constant.WorkflowConstants;
import com.snail.workflow.api.domain.dto.WorkflowDto;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 请假申请Service业务层处理
 * @Author: snail
 * @CreateDate: 2023-09-04
 * @Version: V1.0
 */
@Service
public class LeaveApplyServiceImpl extends ServiceImpl<LeaveApplyMapper, LeaveApply> implements ILeaveApplyService {

    @Autowired
    private SequenceUtils sequenceUtils;
    @Autowired
    private KafkaConsumerService kafkaConsumerService;
    @Autowired
    private KafkaFileConsumerService kafkaFileConsumerService;

    @Override
    public PageResult<LeaveApply> selectLeaveApplyPage(LeaveApplyQuery query) {
        Page<LeaveApply> page = PageUtils.buildPage(query);
        LambdaQueryWrapper<LeaveApply> queryWrapper = new LambdaQueryWrapper<>();
        //单据编码
        queryWrapper.like(StringUtils.isNotEmpty(query.getApplyCode()), LeaveApply::getApplyCode, query.getApplyCode());
        //请假天数
        queryWrapper.eq(query.getLeaveDay() != null, LeaveApply::getLeaveDay, query.getLeaveDay());
        //开始时间
        queryWrapper.ge(StringUtils.isNotEmpty(query.getLeaveBegin()), LeaveApply::getLeaveBegin, query.getLeaveBegin());
        //结束时间
        queryWrapper.le(StringUtils.isNotEmpty(query.getLeaveEnd()), LeaveApply::getLeaveEnd, query.getLeaveEnd());
        //流程状态
        queryWrapper.eq(StringUtils.isNotEmpty(query.getWorkflowStatus()), LeaveApply::getWorkflowStatus, query.getWorkflowStatus());
        //请假人
        queryWrapper.like(StringUtils.isNotEmpty(query.getCreateUserName()), LeaveApply::getCreateUserName, query.getCreateUserName());
        queryWrapper.ge(StringUtils.isNotEmpty(query.getBeginTime()), LeaveApply::getCreateTime, query.getBeginTime());
        queryWrapper.le(StringUtils.isNotEmpty(query.getEndTime()), LeaveApply::getCreateTime, query.getEndTime());
        queryWrapper.orderByDesc(LeaveApply::getCreateTime);
        page = baseMapper.selectPage(page, queryWrapper);
        return PageUtils.pageResult(page);
    }

    @Override
    public LeaveApply getLeaveApplyById(String applyId) {
        return getById(applyId);
    }

    @Override
    public String insertLeaveApply(LeaveApply leaveApply) {
        leaveApply.setApplyName(SecurityUtils.getNickName() + "的" + leaveApply.getLeaveDay() + "天请假申请");
        leaveApply.setWorkflowStatus(WorkflowConstants.STATUS_DRAFT);
        leaveApply.setApplyCode(sequenceUtils.getSequence("LeaveApply"));
        save(leaveApply);
        return leaveApply.getApplyId();
    }

    @Override
    public boolean updateLeaveApply(LeaveApply leaveApply) {
        return updateById(leaveApply);
    }

    @Override
    public boolean deleteLeaveApplyByIds(String[] applyIds) {
        int batch = baseMapper.deleteBatchIds(Arrays.asList(applyIds));
        return batch == applyIds.length;
    }

    @Override
    public List<LeaveApply> selectLeaveApplyList(LeaveApplyQuery query) {
        LambdaQueryWrapper<LeaveApply> queryWrapper = new LambdaQueryWrapper<>();
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public MqResultDto sendMq(String applyId) {
        LeaveApply apply = getById(applyId);
        if(apply == null){
            throw new ServiceException("申请信息为空!");
        }
        MqDto<LeaveApply> mqDto = new MqDto<>();
        //设置业务唯一标识
        mqDto.setPriKey(applyId);
        //设置消息主题
        mqDto.setTopic(KafkaConsumerService.TOPIC);
        //设置消息内容
        mqDto.setContent(apply);
        //设置发送人id
        mqDto.setUserId(SecurityUtils.getUserId());
        //设置发送人名称
        mqDto.setUserName(SecurityUtils.getNickName());
        //发送mq消息
        return kafkaConsumerService.sendMq(mqDto);
    }

    @SneakyThrows
    @Override
    public MqResultDto sendFileMq(MultipartFile file, String applyId) {
        MqDto<String> mqDto = new MqDto<>();
        //设置业务唯一标识
        mqDto.setPriKey(applyId);
        //设置消息主题
        mqDto.setTopic(KafkaFileConsumerService.TOPIC);
        //设置消息内容
        mqDto.setContent(HexUtil.encodeHexStr(file.getBytes()));
        //设置发送人id
        mqDto.setUserId("1");
        //设置发送人名称
        mqDto.setUserName("admin");
        return kafkaFileConsumerService.sendMq(mqDto);
    }

    @Override
    public String getBizWorkflowKey() {
        return "LeaveApply";
    }

    @Override
    public String getBizWorkflowName(String bizId) {
        LeaveApply apply = getById(bizId);
        return apply.getApplyName();
    }

    @Override
    public Map<String, Object> setWorkflowVariables(String bizId) {
        LeaveApply apply = getById(bizId);
        Map<String, Object> variables = new HashMap<>(64);
        variables.put("day",apply.getLeaveDay());
        return variables;
    }

    @Override
    public void afterSubmitTask(WorkflowDto workflowDto, String operationType) {
        LeaveApply leaveApply = new LeaveApply();
        leaveApply.setApplyId(workflowDto.getBizId());
        leaveApply.setWorkflowStatus(workflowDto.getWorkflowStatus());
        this.updateById(leaveApply);
    }

    @Override
    public String checkExcelData(LeaveApply leaveApply) {
        StringBuilder error = new StringBuilder();
        if (leaveApply.getLeaveBegin() == null) {
            error.append("请假开始时间不能为空！");
        }
        if (leaveApply.getLeaveEnd() == null) {
            error.append("请假结束时间不能为空！");
        }
        if (StringUtils.isEmpty(leaveApply.getLeaveReason())) {
            error.append("请假原因不能为空！");
        }
        return error.toString();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveExcelData(List<LeaveApply> dataList) {
        dataList.forEach(item ->{
            Duration duration = Duration.between(item.getLeaveBegin(), item.getLeaveEnd());
            BigDecimal time = BigDecimal.valueOf(duration.toHours());
            item.setLeaveDay(time.divide(BigDecimal.valueOf(8), RoundingMode.UP));
            item.setApplyName(SecurityUtils.getNickName() + item.getLeaveDay() + "天请假申请");
            item.setWorkflowStatus(WorkflowConstants.STATUS_DRAFT);
            item.setApplyCode(sequenceUtils.getSequence("LeaveApply"));
        });
        saveBatch(dataList);
    }
}
